#include "ZComDef.h"
//#include "ssp.h"
#include "OSAL.h"
#include "OSAL_Memory.h"
#include "OnBoard.h"
#include "ZGlobals.h"
#include "osal_Nv.h"
#include "bdb_interface.h"
#include "NLMEDE.h"

#include "mfg.h"
#include "cmd.h"
#include "cmd_uart.h"
#include "cmd_cfg.h"
#include "mfg_coord.h"



/* extern variable */
extern uint8 cmdPktTaskId;

void cmdCfg_DeviceType(uint8 *cmd, uint8 len);
uint8  cmdCfg_Status(void);
uint8  cmdCfg_Channel(bool set, uint8 ch, uint32 *chList);
uint8  cmdCfg_Start(void);
uint8  cmdCfg_Scan(uint32 channel, uint8 duration);
uint8  cmdCfg_Close(void);

void cmdCfg_CmdInput(uint8 cmdSeq, uint8 cmdClass, uint8 cmdLen, uint8* cmdData)
{
  uint8 cmdId = cmdData[0];
  uint8 *p = cmdData + 1;
  uint8 ackLen = 0;
  uint8 acbBuff[128];
  uint8 *pAck = acbBuff + 1;
  uint8 status = ZFailure;
  switch(cmdId)
  {
  case CFG_CMD_STATUS:
    {
      status = cmdCfg_Status();
    }
    break;
    
  case CFG_CMD_CHANNEL:
    {
      bool set = p[0];
      uint32 ch;
      status = cmdCfg_Channel(set, p[1], &ch);
      if(status == ZSuccess)
      {
        pAck[0] = BREAK_UINT32(ch, 0);
        pAck[1] = BREAK_UINT32(ch, 1);
        pAck[2] = BREAK_UINT32(ch, 2);
        pAck[3] = BREAK_UINT32(ch, 3);
        ackLen += 4;
      }
    }
    break;
    
  case CFG_CMD_START:
    {
      status = cmdCfg_Start();
    }
    break;
    
  case CFG_CMD_SCAN:
    {
      uint32 channel = BUILD_UINT32(p[0], p[1], p[2], p[3]);
      uint8 duration = p[4];
      status = cmdCfg_Scan(channel, duration);
    }
    break;
    
  case CFG_CMD_CLOSE:
    {
      status = cmdCfg_Close();
    }
    break;
    
  case CFG_CMD_RECOVER:
    {
      bdb_initialize();
      status = 0;
    }
    break;
    
  default:
    break;
  }
  ackLen += 1;
  acbBuff[0] = status;
  cmd_UartAckSend(cmdSeq,cmdClass,ackLen,acbBuff);
}

void cmdCfg_CmdOutput(uint8 cmdId, uint8 len, uint8* data)
{
  uint8 buf[128];
  buf[0] = cmd_UartGetSeqNum();
  buf[1] = CMD_CLASS_STATUS;
  buf[2] = cmdId;
  
  osal_memcpy( buf+3, data, len );
  cmd_UartTxSend( len+3, buf );
}


/*
  Command print
*/
void cmdCfg_Boot(uint8 boot, uint8 version)
{
  uint8 buf[2];
  buf[0] = boot;
  buf[1] = version;
  zgAllowRemoteTCPolicyChange = FALSE;
  cmdCfg_CmdOutput(CFG_CMD_BOOT, 2, buf );
}

void cmdCfg_CoordStartNotify(uint8 sta, uint8 channel, uint16 panId, uint8 *mac)
{
  nwkKeyDesc tmpKey;
  uint8 buf[12 + SEC_KEY_LEN + 1 + 1];
  uint8 len = 12;
  buf[0] = sta;
  buf[1] = channel;
  buf[2] = LO_UINT16(panId);
  buf[3] = HI_UINT16(panId);
  memcpy(&buf[4], mac, 8);
  if ( NLME_ReadNwkKeyInfo( 0, sizeof(tmpKey), &tmpKey,
                           ZCD_NV_NWK_ACTIVE_KEY_INFO ) == SUCCESS )
  {
    len += SEC_KEY_LEN + 1;
    memcpy(&buf[12], tmpKey.key, SEC_KEY_LEN);
    buf[12 + SEC_KEY_LEN] = tmpKey.keySeqNum;
  }
  len += 1;
  buf[12 + SEC_KEY_LEN + 1] = 0;//Generic_AppVersion;
  cmdCfg_CmdOutput(CFG_CMD_NWK_START, len, buf);
}

void cmdCfg_PermitJoinNotify(uint8 time)
{
  uint8 permit[2];
  permit[0] = time;
  permit[1] = 0;
  if( time == 0 )
  {
    zgAllowRemoteTCPolicyChange = FALSE;
    if( MFG_WhiteListEnable() )
    {
      MFG_WhiteListSet( FALSE );
    }
  }
  if ( !zgAllowRemoteTCPolicyChange )
  {
    permit[1] = 1;
  }
  cmdCfg_CmdOutput(CFG_CMD_PERMIT, 2, permit);
}

void cmdCfg_NodeJoinNotify(uint8* mac, uint16 nodeId, uint16 parent, uint8 mode, uint8 type)
{
  uint8 buf[14];
  osal_memcpy(buf, mac, 8);
  buf[8] = LO_UINT16(nodeId);
  buf[9] = HI_UINT16(nodeId);
  buf[10] = LO_UINT16(parent);
  buf[11] = HI_UINT16(parent);
  buf[12] = mode;
  buf[13] = type;
  cmdCfg_CmdOutput(CFG_CMD_NODE_JOIN, 14, buf);
}

void cmdCfg_DevJoinNotify(bool end, mfgDevSn_t sn, mfgDevAddr_t dev, uint16 profile, uint16 devId,
                          uint8 inNum, uint16 *inCluster, uint8 outNum, uint16 *outCluster)
{
  uint8 buf[80];
  uint8 len = 0;
  uint8 *p = buf;
  uint8 n;

  *p++ = end;
  len += 1;

  memcpy(p, sn, sizeof(mfgDevSn_t));
  p += sizeof(mfgDevSn_t);
  len += sizeof(mfgDevSn_t);

  osal_memcpy(p, dev, sizeof(mfgDevAddr_t));
  p += sizeof(mfgDevAddr_t);
  len += sizeof(mfgDevAddr_t);

  *p++ = LO_UINT16(profile);
  *p++ = HI_UINT16(profile);
  len += 2;

  *p++ = LO_UINT16(devId);
  *p++ = HI_UINT16(devId);
  len += 2;

  *p++ = inNum;
  len+=1;
  for(n=0;n<inNum;n++)
  {
    *p++ = LO_UINT16(inCluster[n]);
    *p++ = HI_UINT16(inCluster[n]);
    len += 2;
  }

  *p++ = outNum;
  len+=1;
  for(n=0;n<outNum;n++)
  {
    *p++ = LO_UINT16(outCluster[n]);
    *p++ = HI_UINT16(outCluster[n]);
    len += 2;
  }

  cmdCfg_CmdOutput(CFG_CMD_DEVICE_JOIN, len, buf);
}

void cmdCfg_LeaveNotify(uint16 nodeId, uint8 *mac, uint16 parent)
{
  uint8 buf[12];
  buf[0] = LO_UINT16(nodeId);
  buf[1] = HI_UINT16(nodeId);
  memcpy(buf+2,mac,8);
  buf[10] = LO_UINT16(parent);
  buf[11] = HI_UINT16(parent);
  cmdCfg_CmdOutput(CFG_CDM_DELETE, 12, buf);
}

void cmdCfg_LeaveInd(NLME_LeaveInd_t ind)
{
  uint8 buf[13];
  buf[0] = LO_UINT16(ind.srcAddr );
  buf[1] = HI_UINT16(ind.srcAddr);
  memcpy(buf+2,ind.extAddr,8);
  buf[10] = ind.request;
  buf[11] = ind.removeChildren;
  buf[12] = ind.rejoin;
  cmdCfg_CmdOutput(CFG_CMD_LEAVE_IND, 13, buf);
}

void cmdCfg_DeviceErro(uint8 *ieee, uint16 nodeId, uint8 ep, uint8 status)
{
  uint8 buf[12];
  memcpy(buf, ieee, 8);
  buf[8] = LO_UINT16(nodeId);
  buf[9] = HI_UINT16(nodeId);
  buf[10] = ep;
  buf[11] = status;
  cmdCfg_CmdOutput(CFG_CMD_DEVICE_ERRO, 12, buf);
}

void cmdCfg_KeyVerify( uint8 status, uint8* extAddr )
{
  uint8 buf[19];
  uint8 len = 9;
  buf[0] = status;
  memcpy( &buf[1], extAddr, 8 );
  cmdCfg_CmdOutput( CFG_CMD_VERIFY_KEY, len, buf );
}

void cmdCfg_Denied( uint8* mac, uint16 parent )
{
  uint8 buf[10];
  memcpy( buf, mac, 8 );
  buf[8] = LO_UINT8( parent );
  buf[9] = HI_UINT8( parent );
  cmdCfg_CmdOutput( CFG_CMD_DENIED, 10, buf );
}

/*
 * Command config
 */
uint8 cmdCfg_Status(void)
{
  if(bdbAttributes.bdbNodeIsOnANetwork)
  {
    return ZSuccess;
  }
  return ZFailure;
}

uint8  cmdCfg_Channel(bool set, uint8 ch, uint32 *chList)
{
  *chList = bdbAttributes.bdbPrimaryChannelSet;
  if( bdbAttributes.bdbNodeIsOnANetwork )
  {
    return ZFailure;
  }
  else if((ch >= 11) && (ch <= 26))
  {
    uint32 chBit = 1<<ch;
    if(set == TRUE)
    {
      *chList |= chBit;
    }
    else
    {
      *chList &= ~chBit;
    }
    bdbAttributes.bdbPrimaryChannelSet = *chList;
  }
  return ZSuccess;
}

uint8 cmdCfg_Start(void)
{
  zgAllowRemoteTCPolicyChange = TRUE;
  if( bdbAttributes.bdbNodeIsOnANetwork )
  {
    bdb_StartCommissioning( BDB_COMMISSIONING_MODE_NWK_STEERING );
  }
  else
  {
    bdb_StartCommissioning( BDB_COMMISSIONING_MODE_NWK_FORMATION );
  }
  return ZSuccess;
}

uint8 cmdCfg_Scan(uint32 channel, uint8 duration)
{
  return ZFailure;
}

uint8 cmdCfg_Close(void)
{
  zgAllowRemoteTCPolicyChange = FALSE;
  zAddrType_t dstAddr;
  dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR_DEVZCZR;
  dstAddr.addrMode = AddrBroadcast;
  // Trust Center significance is always true
  return ZDP_MgmtPermitJoinReq( &dstAddr, 0, TRUE, FALSE );
}








